<template>
  <el-sub-menu :index="props.index">
    <template #title>Entity</template>
    <el-sub-menu index="6-1">
      <template #title>GeoJson</template>
      <el-menu-item index="6-1-1" @click="createArea">GeoJson面数据</el-menu-item>
      <el-menu-item index="6-1-2" @click="createLine">GeoJson线数据</el-menu-item>
      <el-menu-item index="6-1-3" @click="createPoint">GeoJson点数据</el-menu-item>
    </el-sub-menu>
    <el-menu-item index="6-2" @click="createKML">加载KML</el-menu-item>
    <el-menu-item index="6-3" @click="createCZML">加载CZML</el-menu-item>
    <el-menu-item index="6-4" @click="createAirplane">加载飞机</el-menu-item>
    <el-menu-item index="6-5" @click="entitiesPoint">加载点</el-menu-item>
    <el-menu-item index="6-6" @click="createBillboard">加载广告牌</el-menu-item>
    <el-menu-item index="6-7" @click="createLabel">加载标签</el-menu-item>
    <el-menu-item index="6-8" @click="createPolyline">加载折线</el-menu-item>
    <el-menu-item index="6-9" @click="createPolygon">加载多边形</el-menu-item>
    <el-menu-item index="6-10" @click="createBox">加载盒子</el-menu-item>
    <el-menu-item index="6-11" @click="removePolygon">清空entity</el-menu-item>
  </el-sub-menu>
</template>

<script setup>
//Cesium.Entity(options)实体实例将多种形式的可视化聚合到单个高级对象中。
//Entity 是表示地图上对象的基本单位，可以是点、线、面等。每个 Entity 可以有多种属性，如位置、外观等。

// 简单静态数据可用 GeoJSON
// 带样式的静态数据可用 KML
// 复杂的时间动态数据推荐使用 CZML
// 如果只需要表示静态地理数据，GeoJSON 是最简单高效的选择
// 如果需要带样式的静态数据或简单的时间信息，KML 是不错的选择
// 如果需要复杂的动态数据、动画和时间序列，CZML 是最佳选择，特别是在 Cesium 平台上
import * as Cesium from 'cesium'
import { useCesiumStore } from '@/stores/cesiumStore'
import { ref, onMounted, onUnmounted } from 'vue'

// 定义props
const props = defineProps({
  index: {
    type: String,
    required: true,
  },
})

// 使用 Cesium Store
const cesiumStore = useCesiumStore()

// 这是一个 GeoJSON 格式的  面数据对象
const AreaData = {
  type: 'FeatureCollection', // 表示这是一个要素集合
  name: 'shuisi84', // 数据集的名称
  crs: {
    // 坐标参考系统信息
    type: 'name',
    properties: {
      name: 'urn:ogc:def:crs:OGC:1.3:CRS84', // 使用的是 WGS84 坐标系
    },
  },
  features: [
    // 要素数组，包含地理对象
    {
      type: 'Feature', // 表示这是一个地理要素
      properties: {
        // 要素的属性信息
        OBJECTID: 1,
        name: '办公大楼',
        SHAPE_Length: 124.02104107024944,
        SHAPE_Area: 858.0744145512581,
      },
      geometry: {
        // 几何信息
        type: 'MultiPolygon', // 多边形类型
        coordinates: [
          // 坐标数组，这里有两个多边形
          [
            // 第一个多边形
            [
              // 外环坐标
              [109.2041015625, 30.088107753367257], // 经度,纬度
              [115.02685546875, 30.088107753367257],
              [115.02685546875, 32.7872745269555],
              [109.2041015625, 32.7872745269555],
              [109.2041015625, 30.088107753367257], // 闭合多边形
            ],
          ],
          [
            // 第二个多边形
            [
              // 外环坐标
              [112.9833984375, 26.82407078047018],
              [116.69677734375, 26.82407078047018],
              [116.69677734375, 29.036960648558267],
              [112.9833984375, 29.036960648558267],
              [112.9833984375, 26.82407078047018], // 闭合多边形
            ],
          ],
        ],
      },
    },
  ],
}
//加载GeoJSON 面数据
const createArea = async () => {
  try {
    // 使用 async/await 语法处理异步操作
    // Cesium.GeoJsonDataSource.load() 方法可以加载 GeoJSON 数据并创建 DataSource 对象
    // 这里直接传入内存中的 data 对象，而不是从文件加载
    const dataSource = await Cesium.GeoJsonDataSource.load(AreaData) //.load要加载的 url、GeoJSON 对象或 TopoJSON 对象。

    // 将创建的 DataSource 添加到 viewer（Cesium 查看器）中
    // viewer 是 Cesium 应用的主要对象，控制地图显示
    cesiumStore.viewerCesium.dataSources.add(dataSource)

    // 遍历 dataSource 中的所有实体（entities）
    dataSource.entities.values.forEach((entity) => {
      // 生成一个随机颜色，alpha: 1 表示不透明
      const randomColor = Cesium.Color.fromRandom({ alpha: 1 })

      // 检查实体是否有多边形属性
      if (entity.polygon) {
        // 设置多边形的材质为随机颜色
        entity.polygon.material = randomColor

        // 设置多边形轮廓颜色为白色
        entity.polygon.outlineColor = Cesium.Color.WHITE

        // 设置不显示轮廓
        entity.polygon.outline = false

        // 生成 0-5000 之间的随机整数作为高度（单位：米）
        // Math.random() 生成 0-1 之间的随机数
        // Math.floor() 向下取整
        const randomHeight = Math.floor(Math.random() * 5000)

        // 设置多边形的拉伸高度，使其成为 3D 立体
        entity.polygon.extrudedHeight = randomHeight
      }
    })

    // 缩放视图以适应所有数据
    // zoomTo 方法会自动调整相机位置，使所有实体可见
    cesiumStore.viewerCesium.zoomTo(dataSource)

    // 在控制台输出成功消息
    console.log('GeoJSON 数据加载完成')
  } catch (error) {
    // 如果加载过程中出现错误，捕获并在控制台显示
    console.error('加载 GeoJSON 数据时出错:', error)
  }
}
const lineData = {
  type: 'FeatureCollection',
  name: 'xxxxx',
  crs: {
    type: 'name',
    properties: {
      name: 'urn:ogc:def:crs:OGC:1.3:CRS84',
    },
  },
  features: [
    {
      type: 'Feature',
      properties: { desc_: 'xxxxx' },
      geometry: {
        type: 'MultiLineString',
        coordinates: [
          [
            [105.6005859375, 30.65681556429287],
            [107.95166015624999, 31.98944183792288],
            [109.3798828125, 30.031055426540206],
            [107.7978515625, 29.935895213372444],
          ],
        ],
      },
    },
    {
      type: 'Feature',
      properties: { desc_: 'xxxxx' },
      geometry: {
        type: 'MultiLineString',
        coordinates: [
          [
            [109.3798828125, 30.031055426540206],
            [107.1978515625, 31.235895213372444],
          ],
        ],
      },
    },
  ],
}
//加载GeoJSON 线数据
const createLine = async () => {
  try {
    // 使用 async/await 语法处理异步操作
    // 加载 GeoJSON 线数据并创建 DataSource 对象
    const dataSource = await Cesium.GeoJsonDataSource.load(lineData)

    // 将创建的 DataSource 添加到 viewer 中
    cesiumStore.viewerCesium.dataSources.add(dataSource)

    // 在控制台输出 dataSource 对象，便于调试
    console.log(dataSource)

    // 遍历 dataSource 中的所有实体（entities）
    dataSource.entities.values.forEach((entity) => {
      // 检查实体是否有折线属性
      if (entity.polyline) {
        // 设置折线的材质为发光线材质
        entity.polyline.material = new Cesium.PolylineGlowMaterialProperty({
          color: Cesium.Color.BLUE, // 设置线的颜色为蓝色
          glowPower: 0.3, // 发光强度，占总线宽的百分比
          taperPower: 1, // 锥形效果强度，1.0或更高表示不使用锥形效果
        })

        // 设置折线宽度为15像素
        entity.polyline.width = 15
      }
    })

    // 缩放视图以适应所有数据
    cesiumStore.viewerCesium.zoomTo(dataSource)

    // 在控制台输出成功消息
    console.log('GeoJSON 线数据加载完成')
  } catch (error) {
    // 如果加载过程中出现错误，捕获并在控制台显示
    console.error('加载 GeoJSON 线数据时出错:', error)
  }
}
//加载GeoJSON 点数据
const createPoint = async () => {
  try {
    // 定义点数据
    const pointData = {
      type: 'FeatureCollection',
      name: 'shanshanline_point',
      crs: {
        type: 'name',
        properties: {
          name: 'urn:ogc:def:crs:OGC:1.3:CRS84',
        },
      },
      features: [
        {
          type: 'Feature',
          properties: {
            name: '42314545',
          },
          geometry: {
            type: 'Point',
            coordinates: [115.9498226571, 22.903348545499998],
          },
        },
        {
          type: 'Feature',
          properties: {
            name: '432142',
          },
          geometry: {
            type: 'Point',
            coordinates: [115.950796826499996, 22.903378224499999],
          },
        },
        {
          type: 'Feature',
          properties: {
            name: '4123432',
          },
          geometry: {
            type: 'Point',
            coordinates: [115.951770996400001, 22.903407897400001],
          },
        },
        {
          type: 'Feature',
          properties: {
            name: '41234',
          },
          geometry: {
            type: 'Point',
            coordinates: [115.9527451668, 22.903437564400001],
          },
        },
      ],
    }

    // 使用 GeoJsonDataSource 加载点数据
    const dataSource = await Cesium.GeoJsonDataSource.load(pointData, {
      clampToGround: true, // 将点固定在地面上
    })

    // 将数据源添加到查看器
    cesiumStore.viewerCesium.dataSources.add(dataSource)

    // 遍历所有点实体并设置样式
    dataSource.entities.values.forEach((entity, index) => {
      if (entity.position) {
        // 设置点的样式
        entity.billboard = {
          image: '/public/favicon.ico',
          scale: 1.5,
          color: Cesium.Color.fromRandom({ alpha: 1.0 }), // 随机颜色
          verticalOrigin: Cesium.VerticalOrigin.BOTTOM, //图标的垂直对齐方式，BOTTOM 表示图标底部对齐点位置
          heightReference: Cesium.HeightReference.CLAMP_TO_GROUND, // 高度参考 贴地
        }
      }
      // 如果有名称属性，添加标签
      if (entity.properties && entity.properties.name) {
        entity.label = {
          text: entity.properties.name.getValue(), //标签文本，这里使用点的 name 属性
          font: '14pt sans-serif', //字体样式，14pt 大小的无衬线字体
          style: Cesium.LabelStyle.FILL_AND_OUTLINE, //标签样式，FILL_AND_OUTLINE 表示填充并添加轮廓
          outlineWidth: 2, //轮廓宽度为 2 像素
          outlineColor: Cesium.Color.BLACK, //轮廓颜色为黑色
          fillColor: Cesium.Color.WHITE, //填充颜色为白色
          verticalOrigin: Cesium.VerticalOrigin.BOTTOM, //标签的垂直对齐方式，BOTTOM 表示标签底部对齐点位置
          pixelOffset: new Cesium.Cartesian2(0, -80), //标签相对于点的像素偏移
          heightReference: Cesium.HeightReference.CLAMP_TO_GROUND, //高度参考，CLAMP_TO_GROUND 表示标签贴地
        }
      }
    })

    // 缩放视图以适应所有数据
    cesiumStore.viewerCesium.zoomTo(dataSource)

    console.log('GeoJSON 点数据加载完成')
  } catch (error) {
    console.error('加载 GeoJSON 点数据时出错:', error)
  }
}
// 加载KML文件
const createKML = async () => {
  // 设置 KML 加载选项
  const options = {
    camera: cesiumStore.viewerCesium.scene.camera,
    canvas: cesiumStore.viewerCesium.scene.canvas,
  }

  // KML 文件地址
  const kmlUrl = 'http://114.242.26.126:6003/source/kml/bikeRide.kml'

  try {
    // 加载 KML 文件
    const dataSource = await Cesium.KmlDataSource.load(kmlUrl, options)

    // 将数据源添加到查看器
    cesiumStore.viewerCesium.dataSources.add(dataSource)

    // 自定义实体样式
    dataSource.entities.values.forEach((entity) => {
      // 如果实体有 billboard 属性，自定义其样式
      if (entity.billboard) {
        entity.billboard.scale = 1 // 设置图标缩放比例
        entity.billboard.image = '/public/favicon.ico' // 替换为自定义图标
      }

      // 可以在这里添加更多自定义样式，例如：
      // 自定义标签样式
      if (entity.label) {
        entity.label.font = '14pt sans-serif'
        entity.label.style = Cesium.LabelStyle.FILL_AND_OUTLINE
        entity.label.outlineWidth = 2
        entity.label.outlineColor = Cesium.Color.BLACK
        entity.label.fillColor = Cesium.Color.WHITE
      }

      // 自定义线条样式
      if (entity.polyline) {
        entity.polyline.width = 3
        entity.polyline.material = Cesium.Color.BLUE
      }
    })

    // 定位到数据范围  立即将视图调整到目标位置，没有动画过渡
    cesiumStore.viewerCesium.zoomTo(dataSource)

    return dataSource // 返回数据源以便后续操作
  } catch (error) {
    console.error('加载 KML 文件失败:', error)
    return null
  }
}

// 加载CZML文件
const createCZML = async () => {
  try {
    // 加载CZML文件 - 注意这里应该使用CzmlDataSource而不是KmlDataSource
    const dataSource = await Cesium.CzmlDataSource.load(
      'http://114.242.26.126:6003/source/czml/simple.czml',
    )

    // 将数据源添加到查看器
    cesiumStore.viewerCesium.dataSources.add(dataSource)

    // 飞行到数据源
    cesiumStore.viewerCesium.flyTo(dataSource)

    return dataSource
  } catch (error) {
    console.error('加载CZML文件失败:', error)
    throw error
  }
}
//创建点
const entitiesPoint = async () => {
  cesiumStore.viewerCesium.entities.add({
    // 设置点的位置，使用经纬度(经度116.39, 纬度39.9, 高度0)转换为笛卡尔坐标
    position: Cesium.Cartesian3.fromDegrees(116.39, 39.9, 0),
    // 点的样式配置
    point: {
      pixelSize: 10, // 点的像素大小
      color: Cesium.Color.RED, // 点的颜色：红色
      outlineColor: Cesium.Color.WHITE, // 点的轮廓颜色：白色
      outlineWidth: 2, // 点的轮廓宽度：2像素
    },
  })
  // cesiumStore.viewerCesium.camera.flyTo({
  //   // 设定相机的目的地    // /fromDegrees 根据以度为单位给出的经度和纬度值返回 Cartesian3 位置 {x: -2850140.3007405344, y: 4655805.925395274, z: 3290571.0927250083}
  //   destination: Cesium.Cartesian3.fromDegrees(116.39, 39.9, 0),
  // })
}

//广告牌
const createBillboard = async () => {
  cesiumStore.viewerCesium.entities.add({
    // 设置广告牌的位置，使用经纬度(经度106.63, 纬度29.57, 高度0)转换为笛卡尔坐标
    position: Cesium.Cartesian3.fromDegrees(106.62672254553621, 29.572460283514193, 0),
    // 广告牌的样式配置
    billboard: {
      image: '/src/assets/images/icon/Logo_icon.png', // 广告牌图片路径
      width: 50, // 宽度：50像素
      height: 50, // 高度：50像素
      scale: 1.0, // 缩放比例：1.0倍
      rotation: 0, // 旋转角度：0弧度
      horizontalOrigin: Cesium.HorizontalOrigin.CENTER, // 水平对齐方式：居中
      verticalOrigin: Cesium.VerticalOrigin.BOTTOM, // 垂直对齐方式：底部对齐
    },
  })
}

//标签
const createLabel = async () => {
  cesiumStore.viewerCesium.entities.add({
    // 设置标签的位置，使用经纬度(经度116.39, 纬度39.9, 高度0)转换为笛卡尔坐标
    position: Cesium.Cartesian3.fromDegrees(116.39, 39.9, 0),
    // 标签的样式配置
    label: {
      text: '北京', // 标签文本内容
      font: '14pt sans-serif', // 字体样式：14pt无衬线字体
      fillColor: Cesium.Color.WHITE, // 填充颜色：白色
      outlineColor: Cesium.Color.BLACK, // 轮廓颜色：黑色
      outlineWidth: 2, // 轮廓宽度：2像素
      style: Cesium.LabelStyle.FILL_AND_OUTLINE, // 标签样式：填充并显示轮廓
      horizontalOrigin: Cesium.HorizontalOrigin.CENTER, // 水平对齐方式：居中
      verticalOrigin: Cesium.VerticalOrigin.BOTTOM, // 垂直对齐方式：底部对齐
      pixelOffset: new Cesium.Cartesian2(0, -10), // 像素偏移量：向上偏移10像素
    },
  })
}
//折线
// 创建折线实体
const createPolyline = async () => {
  cesiumStore.viewerCesium.entities.add({
    // 折线的样式配置
    polyline: {
      // 设置折线的位置点数组，使用经纬度数组转换为笛卡尔坐标数组
      // 格式为[经度1, 纬度1, 经度2, 纬度2, ...]
      positions: Cesium.Cartesian3.fromDegreesArray([116.38, 39.89, 116.4, 39.91]),
      width: 5, // 折线宽度：5像素
      material: Cesium.Color.BLUE, // 折线材质：蓝色
    },
  })
}
//多边形
const Polygons = ref(null)
// 创建多边形实体
const createPolygon = async () => {
  Polygons.value = cesiumStore.viewerCesium.entities.add({
    id: 'polygon', //entities.getById('polygon').polygon.material = Cesium.Color.RED;
    // 多边形的样式配置
    polygon: {
      // 设置多边形的顶点层次结构，使用经纬度数组转换为笛卡尔坐标数组
      // 格式为[经度1, 纬度1, 经度2, 纬度2, ...]，首尾点会自动闭合
      hierarchy: Cesium.Cartesian3.fromDegreesArray([
        116.38, 39.89, 116.4, 39.89, 116.4, 39.91, 116.38, 39.91,
      ]),
      material: Cesium.Color.RED.withAlpha(0.5), // 多边形材质：半透明红色
      outline: true, // 是否显示轮廓：是
      outlineColor: Cesium.Color.BLACK, // 轮廓颜色：黑色
      // extrudedHeight: 1000, // 拉伸高度：1000米
    },
  })
  cesiumStore.viewerCesium.camera.flyTo({
    // 设定相机的目的地    // /fromDegrees 根据以度为单位给出的经度和纬度值返回 Cartesian3 位置
    destination: Cesium.Cartesian3.fromDegrees(
      116.38, // 经度
      39.89, // 纬度
      5000, // 高度（米）
    ),
  })
}

//删除所有
const removePolygon = () => {
  // cesiumStore.viewerCesium.entities.remove(Polygons.value)  //多边形
  cesiumStore.viewerCesium.entities.removeAll()
}

// 创建盒子实体
const createBox = async () => {
  cesiumStore.viewerCesium.entities.add({
    // 设置盒子的中心位置，使用经纬度(经度116.39, 纬度39.9, 高度50)转换为笛卡尔坐标
    position: Cesium.Cartesian3.fromDegrees(116.39, 39.9, 50),
    // 盒子的样式配置
    box: {
      dimensions: new Cesium.Cartesian3(1000000.0, 1000000.0, 1000000.0), // 盒子尺寸：长宽高各100米
      material: Cesium.Color.RED.withAlpha(0.5), // 盒子材质：半透明红色
      outline: true, // 是否显示轮廓：是
      outlineColor: Cesium.Color.BLACK, // 轮廓颜色：黑色
    },
    // 简单文本描述
    description: '这是一个盒子', //主要用于为实体（Entity）提供描述性信息  支持自定义html `<div> </div>`和样式
  })
}
//创建飞机
const createAirplane = async () => {
  const position = Cesium.Cartesian3.fromDegrees(
    106.62672254553621, // 经度
    29.572460283514193, // 纬度
    3073.8116032563867, // 高度（米）
  )
  //Transforms.headingPitchRollQuaternion(局部参考系的中心点。,航向、俯仰和滚动。) 从参考系计算四元数，其轴根据以提供原点为中心的航向-俯仰-滚动角度计算
  //Cesium.Transforms.headingPitchRollQuaternion 将这些角度转换为四元数
  const orientation = Cesium.Transforms.headingPitchRollQuaternion(
    position,
    new Cesium.HeadingPitchRoll(-90, 0, 0), //Cesium.HeadingPitchRoll 创建了一个表示航向(heading)、俯仰(pitch)和滚转(roll)角度的对象  向西 水平 无倾斜
  )
  await cesiumStore.viewerCesium.entities.add({
    position: position,
    orientation: orientation,
    model: {
      uri: '/public/glb/Cesium_Air.glb',
      minimumPixelSize: 64,
      show: true,
    },
  })
  const heading = 2.2010704466764235
  const pitch = -0.4082165959392512
  const range = 50 // 高度
  cesiumStore.viewerCesium.camera.lookAt(
    //使用目标和偏移设置相机位置和方向
    position,
    new Cesium.HeadingPitchRange(heading, pitch, range), //以目标为中心的本地东西向向上参考系中与目标的偏移量。
  ) //  设置相机方向和高度的方法

  // cesiumStore.viewerCesium.flyTo(a)
}
</script>

<style lang="scss" scoped></style>
